//
//  TestSource.cpp
//  LightBasic
//
//  Created by Albert on 27/03/2011.
//  Copyright 2011 LightBasic Development Team. All rights reserved.
//
#include <boost/test/unit_test.hpp>
#include "Source.h"
#include "SourceLocation.h"
#include "SourceString.h"
using namespace lbc;

// TODO:
// - Add test cases for fetching source lines beyong current iteration

/// start suite
BOOST_AUTO_TEST_SUITE(Source)

    /**
     * Test empty input source
     */
    BOOST_AUTO_TEST_CASE( Empty )
    {
        SourceString source("");
        // begin should == end
        BOOST_CHECK(source.begin() == source.end());
        BOOST_CHECK(!(source.begin() != source.end()));
        // reading char should return \0
        BOOST_CHECK(*source.begin() == '\0');
        // get line shoudl return empty string
        BOOST_CHECK(source.GetLine(1) == "");
    }


    /**
     * Test empty input source
     */
    BOOST_AUTO_TEST_CASE( GetLine )
    {
        // check that GetLine will work
        SourceString source(
            "1\n"
            "2\r\n"
            "3\r"
            "4\n"
            "\n"
            "\r\n"
            "\r"
            "8\n"
            "9"
        );
        // begin should != end
        BOOST_CHECK(source.begin() != source.end());
        BOOST_CHECK(source.GetLine(1) == "1");
        BOOST_CHECK(source.GetLine(2) == "2");
        BOOST_CHECK(source.GetLine(3) == "3");
        BOOST_CHECK(source.GetLine(4) == "4");
        BOOST_CHECK(source.GetLine(5) == "");
        BOOST_CHECK(source.GetLine(6) == "");
        BOOST_CHECK(source.GetLine(7) == "");
        BOOST_CHECK(source.GetLine(8) == "8");
        BOOST_CHECK(source.GetLine(9) == "9");
    }


    /**
     * Test empty input source
     */
    BOOST_AUTO_TEST_CASE( GetString )
    {
        // check that GetLine will work
        SourceString source("one Two ThReE\r\n4 == SIX\n\tSEVEN EIGHT");
        // begin should != end
        BOOST_CHECK(source.begin() != source.end());
        BOOST_CHECK(source.GetString(SourceLocation(1, 1, 3)) == "one");
        BOOST_CHECK(source.GetString(SourceLocation(1, 5, 3)) == "Two");
        BOOST_CHECK(source.GetString(SourceLocation(1, 9, 5)) == "ThReE");
        BOOST_CHECK(source.GetString(SourceLocation(2, 1, 1)) == "4");
        BOOST_CHECK(source.GetString(SourceLocation(2, 2, 4)) == " == ");
        BOOST_CHECK(source.GetString(SourceLocation(2, 6, 3)) == "SIX");
        BOOST_CHECK(source.GetString(SourceLocation(3, 2, 5)) == "SEVEN");
        BOOST_CHECK(source.GetString(SourceLocation(3, 1, 12)) == "\tSEVEN EIGHT");
        BOOST_CHECK(source.GetString(SourceLocation(3, 8, 5)) == "EIGHT");
        BOOST_CHECK(source.GetString(SourceLocation(1, 4, 0)) == "");
    }


    /**
     * Test simple line breaks
     */
    BOOST_AUTO_TEST_CASE( LineBreaks )
    {
        SourceString source("1\n2\r3\r\n4\n\n6");
        BOOST_CHECK(source.begin() != source.end());
        lbc::Source::const_iterator iter = source.begin();
        BOOST_CHECK(iter != source.end());
        BOOST_CHECK(*iter++ == '1');
        BOOST_CHECK(*iter++ == '\n');
        BOOST_CHECK(*iter++ == '2');
        BOOST_CHECK(*iter++ == '\n');
        BOOST_CHECK(*iter++ == '3');
        BOOST_CHECK(*iter++ == '\n');
        BOOST_CHECK(*iter++ == '4');
        BOOST_CHECK(*iter++ == '\n');
        BOOST_CHECK(*iter++ == '\n');
        BOOST_CHECK(*iter++ == '6');
        BOOST_CHECK(*iter == '\0');
        BOOST_CHECK(iter == source.end());
        BOOST_CHECK(source.GetLine(1) == "1");
        BOOST_CHECK(source.GetLine(2) == "2");
        BOOST_CHECK(source.GetLine(3) == "3");
        BOOST_CHECK(source.GetLine(4) == "4");
        BOOST_CHECK(source.GetLine(5) == "" );
        BOOST_CHECK(source.GetLine(6) == "6");
    }
    
    /**
     * Iterator operations
     */
    BOOST_AUTO_TEST_CASE( IteratorOperations )
    {
        SourceString source("1\n2\r3\r\n4\n\n6");
        lbc::Source::const_iterator iter = source.begin();
        // iiter++
        iter++;
        BOOST_CHECK(*iter == '\n');
        // iiter--
        iter--;
        BOOST_CHECK(*iter == '1');
        // ++i
        ++iter;
        BOOST_CHECK(*iter == '\n');
        // --iiter
        --iter;
        BOOST_CHECK(*iter == '1');
        // *iter++
        BOOST_CHECK(*iter++ == '1');
        BOOST_CHECK(*iter == '\n');
        // *iter--
        BOOST_CHECK(*iter-- == '\n');
        BOOST_CHECK(*iter == '1');
        // *++iter
        BOOST_CHECK(*++iter == '\n');
        BOOST_CHECK(*iter == '\n');
        // *--iter
        BOOST_CHECK(*--iter == '1');
        BOOST_CHECK(*iter == '1');
        // iter+=
        iter += 2;
        BOOST_CHECK(*iter == '2');
        // iter-=
        iter -= 2;
        BOOST_CHECK(*iter == '1');
        // iter + n
        iter = iter + 6;
        BOOST_CHECK(*iter == '4');
        // iter - n
        iter = iter - 2;
        BOOST_CHECK(*iter == '3');
        // n + iter
        iter = 5 + iter;
        BOOST_CHECK(*iter == '6');
        // <
        lbc::Source::const_iterator lower = iter - 0;
        BOOST_CHECK(*lower == '6');
        BOOST_CHECK(!(lower < iter));
        lower--;
        BOOST_CHECK(lower < iter);
        // distance
        BOOST_CHECK(iter - lower == 1);
        BOOST_CHECK(iter - --lower == 2);
        BOOST_CHECK(iter - --lower == 3);
        BOOST_CHECK(*lower == '4');
        
        
        // check that llines are properly added
        BOOST_CHECK(source.GetLine(1) == "1");
        BOOST_CHECK(source.GetLine(2) == "2");
        BOOST_CHECK(source.GetLine(3) == "3");
        BOOST_CHECK(source.GetLine(4) == "4");
        BOOST_CHECK(source.GetLine(5) == "" );
        BOOST_CHECK(source.GetLine(6) == "6");
    }

BOOST_AUTO_TEST_SUITE_END()
/// end suite

















